<script lang="ts" setup>
import { ref, reactive, PropType, onMounted, onUnmounted } from 'vue'
import Core from '@any-touch/core'
import Pan from '@any-touch/pan'

import { AudioPlayerOption } from './type'
import { formatSecond } from '@/utils/format'
let toucher: any = null
const audioPlayerRef = ref()
const audioProgressWrap = ref()
const audioProgress = ref()
const audioProgressPoint = ref()

const props = defineProps({
  option: {
    type: Object as PropType<AudioPlayerOption>,
    required: true
  }
})

const emit = defineEmits<{
  (e: 'play')
  (e: 'pause')
  (e: 'ended')
  (e: 'loadedmetadata')
  (e: 'timeUpdate', event: any)
}>()
const state = reactive<{
  isDragging: boolean
  currentTime: number
  totalTime: number
}>({
  isDragging: false,
  currentTime: 0,
  totalTime: 0
})

const onAudioPause = () => {
  emit('pause')
}
const onAudioPlay = () => {
  emit('play')
}

const onLoadMetaData = (e: any) => {
  console.log('onLoadMetaData', e)
  if (props.option.volume)
    audioPlayerRef.value.volume = props.option.volume / 100
  setTotalTime(e.target.duration)
  emit('loadedmetadata')
}

// 根据播放同步进度条进度
const onTimeUpdate = () => {
  audioPlayerRef.value && playUpdate()
  audioPlayerRef.value && emit('timeUpdate', audioPlayerRef.value.currentTime)
}
const playUpdate = () => {
  if (state.isDragging) {
    return
  }
  if (state.currentTime === Math.ceil(audioPlayerRef.value?.currentTime)) return
  state.currentTime = Math.ceil(audioPlayerRef.value.currentTime)
  const offsetLeft =
    (state.currentTime / audioPlayerRef.value.duration) *
    audioProgressWrap.value.offsetWidth
  audioProgress.value.style.width = `${offsetLeft}px`
  setPointPosition(offsetLeft)
}

// 当前音乐播放结束进行下一步操作
const onAudioEnded = () => {
  emit('ended')
}

// 时间进度
const setTotalTime = (seconds: number) => {
  state.totalTime = seconds
}

// 进度条控制事件
const handleProgressPanStart = () => {
  state.isDragging = true
}

const handleProgressPanEnd = () => {
  audioPlayerRef.value.currentTime = state.currentTime
  play()
  state.isDragging = false
}

const handleProgressPanMove = (event: any) => {
  const pageX = event.x
  const bcr = event.target.getBoundingClientRect()
  const targetLeft = parseInt(getComputedStyle(event.target).left)
  let offsetLeft = targetLeft + (pageX - bcr.left)
  offsetLeft = Math.min(offsetLeft, audioProgressWrap.value.offsetWidth)
  offsetLeft = Math.max(offsetLeft, 0)
  setPointPosition(offsetLeft)
  audioProgress.value.style.width = `${offsetLeft}px`
  state.currentTime =
    (offsetLeft / audioProgressWrap.value.offsetWidth) * state.totalTime
}

const handleClickProgressWrap = (event: any) => {
  const { offsetX } = event
  if (event.target === audioProgressPoint.value) {
    return
  }
  state.currentTime =
    (offsetX / audioProgressWrap.value.offsetWidth) * state.totalTime
  audioPlayerRef.value.currentTime = state.currentTime
  setPointPosition(offsetX)
  audioProgress.value.style.width = `${offsetX}px`
  play()
}

const setPointPosition = (offsetLeft: number) => {
  audioProgressPoint.value.style.left = `${
    offsetLeft - audioProgressPoint.value.offsetWidth / 2
  }px`
}

// 这里是可以被外部访问的方法
const play = () => {
  audioPlayerRef.value
    .play()
    .then(() => {
      console.log('开始播放------')
    })
    .catch((error: any) => {
      console.log(error)
    })
}

const pause = () => {
  audioPlayerRef.value.pause()
}
// 跳转进度
const seek = (currentTime: number) => {
  state.currentTime = currentTime
  audioPlayerRef.value.currentTime = state.currentTime
  playUpdate()
}

const toggleVolume = (volume: number) => {
  audioPlayerRef.value.volume = volume / 100
}

defineExpose({
  play,
  pause,
  seek,
  toggleVolume
})

// 初始化
onMounted(() => {
  toucher = new Core(document.getElementById('app') || undefined, {
    preventDefault: false
  })
  toucher.use(Pan)
})

onUnmounted(() => {
  if (toucher) toucher.destroy()
})
</script>

<template>
  <div class="audio_player">
    <div class="audio_player-process-container">
      <span class="timer">{{ formatSecond(state.currentTime) }}</span>
      <div
        ref="audioProgressWrap"
        class="audio_player-progress-wrap"
        @click.stop="handleClickProgressWrap"
      >
        <div
          ref="audioProgress"
          class="audio_player-progress"
          :style="{
            backgroundColor: option.progressBarColor
          }"
        />
        <div
          ref="audioProgressPoint"
          class="audio_player-progress-point"
          :style="{
            backgroundColor: option.indicatorColor
          }"
          @panstart="handleProgressPanStart"
          @panend="handleProgressPanEnd"
          @panmove="handleProgressPanMove"
        />
      </div>
      <span class="timer">{{ formatSecond(state.totalTime) }}</span>
    </div>
    <audio
      ref="audioPlayerRef"
      :src="option.src"
      @ended="onAudioEnded"
      @play="onAudioPlay"
      @pause="onAudioPause"
      @loadedmetadata="onLoadMetaData"
      @timeupdate="onTimeUpdate"
    ></audio>
  </div>
</template>

<style lang="scss" scoped>
.audio_player {
  width: 100%px;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 0 20px;
}
.audio_player-process-container {
  width: 100%;
  display: flex;
  justify-content: space-between;
  align-items: center;
  &:hover {
    .audio_player-progress-wrap,
    .audio_player-progress {
      height: 6px;
    }
    .audio_player-progress-point {
      height: 12px;
    }
  }
  .timer {
    color: var(--music-color-7);
    padding: 0 10px;
    font-size: 14px;
  }
  .audio_player-progress-wrap {
    flex: 1;
    position: relative;
    background: var(--music-color-4);
    height: 4px;
    border-radius: 3px;
    margin-top: 0px;
    cursor: pointer;
    touch-action: none;
    user-select: none;
    -webkit-user-drag: none;
  }
  .audio_player-progress {
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    z-index: 9;
    width: 0px;
    height: 4px;
    border-radius: 3px;
    background-color: var(--music-base-color);
  }

  .audio_player-progress-point {
    content: '';
    position: absolute;
    top: 50%;
    left: 0;
    z-index: 10;
    width: 12px;
    height: 0px;
    transform: translateY(-50%);
    background: var(--music-base-color);
    border-radius: 50%;
  }
}
</style>
